home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Disc to the Future 2
/
Disc to the Future Part II Programmer's Reference (Wayzata Technology)(6013)(1992).bin
/
MAC
/
MPW_TOOL
/
TOOLS
/
TOOLS_WI
/
ICON_8
/
ICONX_FO
/
RMEMEXP.C
< prev
next >
Wrap
Text File
|
1990-03-11
|
13KB
|
445 lines
/*
* File: rmemexp.c - memory management functions for expandable regions
* Contents: initalloc, reclaim, malloc, calloc, free
*/
/*
* Prototypes.
*/
hidden novalue moremem Params((uword units));
hidden novalue reclaim Params((int region));
word xcodesize;
/*
* initalloc - initialization routine to allocate memory regions
*/
novalue initalloc(codesize)
word codesize;
{
xcodesize = codesize;
/*
* Establish icode region
*/
code = (char *)sbrk((word)0);
/*
* Set up allocated memory. The regions are:
*
* Static memory region
* Allocated string region
* Allocate block region
* Qualifier list
*/
statfree = statbase = (char *)((uword)(code + codesize + 3) & ~03);
/*
* The following code is operating-system dependent [@rmemexp.01]. Set end of
* static region, rounding up if necessary.
*/
#if PORT
statend = (char *)(((uword)statbase) + mstksize + statsize);
Deliberate Syntax Error
#endif /* PORT */
#if AMIGA || HIGHC_386 || MVS || OS2 || VM
/* uses FixedRegions */
#endif /* AMIGA || HIGHC_386 || ... */
#if MSDOS
statend =
(char *)(((uword)statbase) + (((mstksize + statsize + 511)/512) * 512));
#endif /* MSDOS */
#if MACINTOSH
#if MPW
statend = (char *)(((uword)statbase) + mstksize + statsize);
#endif /* MPW */
#endif /* MACINTOSH */
#if ATARI_ST || UNIX || VMS
statend = (char *)(((uword)statbase) + mstksize + statsize);
#endif /* ATARI_ST || UNIX || VMS */
/*
* End of operating-system specific code.
*/
strfree = strbase = (char *)((uword)(statend + 63) & ~077);
blkfree = blkbase = strend = (char *)((((uword)strbase) + ssize +
63) & ~077);
equallist = (dptr *)(blkend =
(char *)((((uword)(blkbase) + abrsize + 63)) & ~077));
/*
* Try to move the break back to the end of memory to allocate (the
* end of the string qualifier list) and die if the space isn't
* available.
*/
if ((int)brk((char *)equallist) == -1)
error("insufficient memory");
currend = (char *)sbrk((word)0); /* keep track of end of memory */
}
/*
* reclaim - reclaim space in the allocated memory regions. The marking
* phase has already been completed.
*/
static novalue reclaim(region)
int region;
{
register word stat_extra, str_extra, blk_extra;
register char *newend;
stat_extra = 0;
str_extra = 0;
blk_extra = 0;
/*
* Collect available co-expression blocks.
*/
cofree();
/*
* If there was no room to construct the qualifier list, the string
* region cannot be collected and the static region cannot be expanded.
*/
if (!qualfail) {
/*
* Check whether the static region needs to be expanded. Regions cannot
* be expanded if someone else has moved the end of allocated storage.
*/
if (statneed && currend == sbrk((word)0)) {
/*
* Make sure there is space for the requested static region expansion.
* The check involving equallist and newend appears to only be
* required on machines where the above addition of statneed might
* overflow.
*/
newend = (char *)equallist + statneed;
if ((uword)newend >= (uword)(char *)equallist &&
(int)brk((char *)newend) != -1) {
stat_extra = statneed;
statneed = 0;
statend += stat_extra;
equallist = (dptr *)newend;
currend = sbrk((word)0);
}
}
/*
* Collect the string space, indicating that it must be moved back
* extra bytes.
*/
scollect(stat_extra);
if (region == Strings && currend == sbrk((word)0)) {
/*
* Calculate a value for extra space. The value is (the larger of
* (twice the string space needed) or (a quarter of the string space))
* minus the unallocated string space.
*/
str_extra = (Max(2*strneed, ((uword)strend - (uword)strbase)/4) -
((uword)strend - (uword)strfree) + (GranSize-1)) & ~(GranSize-1);
while (str_extra > 0) {
/*
* Try to get str_extra more bytes of storage. If it can't be
* gotten, decrease the value by GranSize and try again. If
* it's gotten, move back equallist.
*/
newend = (char *)equallist + str_extra;
if ((uword)newend >= (uword)(char *)equallist &&
(int)brk((char *)newend) != -1) {
equallist = (dptr *) newend;
currend = sbrk((word)0);
break;
}
str_extra -= GranSize;
}
if (str_extra < 0)
str_extra = 0;
}
}
/*
* Adjust the pointers in the block region.
*/
adjust(blkbase, blkbase + stat_extra + str_extra);
/*
* Compact the block region.
*/
compact(blkbase);
if (region == Blocks && currend == sbrk((word)0)) {
/*
* Calculate a value for extra space. The value is (the larger of
* (twice the block region space needed) or (one quarter of the
* block region)) plus the unallocated block space.
*/
blk_extra = (Max(2*blkneed, ((uword)blkend - (uword)blkbase)/4) -
((uword)blkend - (uword)blkfree) + (GranSize-1)) & ~(GranSize-1);
while (blk_extra > 0) {
/*
* Try to get blk_extra more bytes of storage. If it can't be gotten,
* decrease the value by GranSize and try again. If it's gotten,
* move back equallist.
*/
newend = (char *)equallist + blk_extra;
if ((uword)newend >= (uword)(char *)equallist &&
(int)brk((char *)newend) != -1) {
equallist = (dptr *) newend;
currend = sbrk((word)0);
break;
}
blk_extra -= GranSize;
}
if (blk_extra < 0)
blk_extra = 0;
}
if (stat_extra + str_extra > 0) {
/*
* The block region must be moved. There is an assumption here that the
* block region always moves up in memory, i.e., the static and
* string regions never shrink. With this assumption in hand,
* the block region must be moved before the string space lest the
* string space overwrite block data. The assumption is valid,
* but beware if shrinking regions are ever implemented.
*/
mvc((uword)blkfree - (uword)blkbase, blkbase, blkbase + stat_extra +
str_extra);
blkbase += stat_extra + str_extra;
blkfree += stat_extra + str_extra;
}
blkend += stat_extra + str_extra + blk_extra;
if (stat_extra > 0) {
/*
* The string space must be moved up in memory.
*/
mvc((uword)strfree - (uword)strbase, strbase, strbase + stat_extra);
strbase += stat_extra;
strfree += stat_extra;
}
strend += stat_extra + str_extra;
}
/*
* These are Icon's own versions of the allocation routines. They are
* not used for the fixed-regions versions of memory management. They
* normally overload the corresponding library routines. If this is not
* possible, they are re-named and calls to them are renamed.
*/
static HEADER base; /* start with empty list */
static HEADER *allocp = NULL; /* last allocated block */
pointer malloc(nbytes)
msize nbytes;
{
register HEADER *p, *q;
register uword nunits;
register pointer xbase;
int attempts;
if (statbase == NULL) {
if ((xbase = sbrk(nbytes)) == (pointer)-1)
syserr("malloc: failed during startup");
return xbase;
}
nunits = 1 + (nbytes + sizeof(HEADER) - 1) / sizeof(HEADER);
if ((q = allocp) == NULL) { /* no free list yet */
base.s.ptr = allocp = q = &base;
base.s.bsize = 0;
}
for (attempts = 2; attempts--; q = allocp) {
for (p = q->s.ptr;; q = p, p = p->s.ptr) {
if (p->s.bsize >= nunits) { /* block is big enough */
if (p->s.bsize == nunits) /* exactly right */
q->s.ptr = p->s.ptr;
else { /* allocate tail end */
p->s.bsize -= nunits;
p += p->s.bsize;
p->s.bsize = nunits;
}
allocp = q;
#ifdef MemMon
if (nunits > 1) {
MMStat((char *)(p + 1), (word) nbytes, 'A');
*(int *)(p + 1) = 0; /* clear FREEMAGIC flag */
}
#endif /* MemMon */
return (char *)(p + 1);
}
if (p == allocp) { /* wrap around */
moremem(nunits); /* garbage collect and expand if needed */
break;
}
}
}
return NULL;
}
#define FREESIZE 2 /* units sizeof(HEADER) that justify free() */
/*
* realloc() allocates a block of memory of a requested size (amount) to
* contain the contents of the current block (curmem) or as much as will
* fit. Blocks are allocated in units of sizeof(HEADER)
*/
pointer realloc(curmem,newsiz)
register pointer curmem; /* the current memory pointer */
msize newsiz; /* bytes needed for new allocation */
{
register int cunits; /* currently allocated units */
register int nunits; /* new units required */
char *newmem; /* the new memory pointer */
register HEADER *head; /* all blocks used or free have a header */
/*
* First establish the unit sizes involved.
*/
nunits = 1 + (newsiz + sizeof(HEADER) - 1) / sizeof(HEADER);
head = ((HEADER *)curmem) - 1; /* move back a block header */
cunits = (int)head->s.bsize;
/*
* Now allocate or free space as required.
*/
if (nunits <= cunits) { /* we already have the space */
if (cunits - nunits < FREESIZE)
return curmem;
else { /* free space at end of current block */
head->s.bsize = nunits; /* reduce space used */
head += nunits; /* move to free space */
head->s.bsize = cunits - nunits;
free((pointer)(++head)); /* free this new block */
return curmem;
}
}
else { /* more space needed */
if ((newmem = malloc((msize)newsiz)) != NULL) {
memcopy(newmem,curmem,(word)((cunits - 1) * sizeof(HEADER)));
free(curmem);
return newmem;
}
}
return NULL;
}
/*
* calloc() allocates ecnt number of esiz-sized chunks of zero-initialized
* memory for an array of ecnt elements.
*/
pointer calloc(ecnt,esiz)
register msize ecnt, esiz;
{
register char *mem; /* the memory pointer */
register msize amount; /* the amount of memory needed */
amount = ecnt * esiz;
if ((mem = malloc(amount)) != NULL) {
memfill(mem,0,(word)amount); /* initialize it to zero */
return mem;
}
return NULL;
}
static novalue moremem(nunits)
uword nunits;
{
register HEADER *up;
register word rnu;
word n;
rnu = NALLOC * ((nunits + NALLOC - 1) / NALLOC);
n = rnu * sizeof(HEADER);
if (((uword)statfree) + n > (uword)statend) {
statneed = ((n / statincr) + 1) * statincr;
coll_stat++;
collect(Static);
}
/*
* See if there is any room left.
*/
if ((uword)statend - (uword)statfree > sizeof(HEADER)) {
up = (HEADER *) statfree;
up->s.bsize = ((uword)statend - (uword)statfree) / sizeof(HEADER);
statfree = (char *) (up + up->s.bsize);
free((pointer)(up + 1)); /* add block to free memory */
}
}
#if LATTICE || LSC
#define nothing 0
int free(ap)
#else /* LATTICE || LSC */
#define nothing
novalue free(ap) /* return block pointed to by ap to free list */
#endif /* LATTICE || LSC */
pointer ap;
{
register HEADER *p, *q;
/* free may be called to free a block before the static region is
* initialized.
*/
if (statbase == (char *)NULL || (char *)ap < statbase)
return nothing;
p = (HEADER *)ap - 1; /* point to header */
#ifdef MemMon
if (p->s.bsize > 1) {
if (*(int *)(p + 1) != T_Coexpr)
MMStat((char *)ap, (word)((p->s.bsize - 1) * sizeof(HEADER)), 'F');
*(int *)(p + 1) = FREEMAGIC;
}
#endif /* MemMon */
if (p->s.bsize * sizeof(HEADER) >= statneed)
statneed = 0;
for (q = allocp; !((uword)p > (uword)q && (uword)p < (uword)q->s.ptr);
q = q->s.ptr)
if ((uword)q >= (uword)q->s.ptr && ((uword)p > (uword)q ||
(uword)p < (uword)q->s.ptr))
break; /* at one end or the other */
if ((uword)p + sizeof(HEADER) * p->s.bsize
== (uword)q->s.ptr) { /* join to upper */
p->s.bsize += q->s.ptr->s.bsize;
if (p->s.bsize * sizeof(HEADER) >= statneed)
statneed = 0;
p->s.ptr = q->s.ptr->s.ptr;
}
else
p->s.ptr = q->s.ptr;
if ((uword)q + sizeof(HEADER) * q->s.bsize ==
(uword)p) { /* join to lower */
q->s.bsize += p->s.bsize;
if (q->s.bsize * sizeof(HEADER) >= statneed)
statneed = 0;
q->s.ptr = p->s.ptr;
}
else
q->s.ptr = p;
allocp = q;
}